from datetime import datetime
import hashlib
from flask import json
from exts import db
from sqlalchemy.dialects.mysql import JSON
from werkzeug.security import generate_password_hash, check_password_hash
from sqlalchemy import func


# 动物模型，表示数据库中动物信息的表结构
class animal(db.Model):
    # 定义字段
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)  # 动物ID，主键，自增
    全名 = db.Column(db.String(255))  # 动物全名
    别名 = db.Column(db.String(255))  # 动物别名
    分类 = db.Column(db.String(255))  # 动物分类
    体型 = db.Column(db.String(255))  # 动物体型描述
    毛发 = db.Column(db.String(255))  # 动物毛发描述
    智商 = db.Column(db.String(255))  # 动物智商描述
    寿命 = db.Column(db.String(255))  # 动物寿命描述
    饲养 = db.Column(db.String(255))  # 动物饲养难易程度
    功能 = db.Column(db.String(255))  # 动物功能或用途
    原产地 = db.Column(db.String(255))  # 动物原产地
    价格 = db.Column(db.String(255))  # 动物价格
    imgUrl = db.Column(db.String(255))  # 动物图片URL
    imgPath = db.Column(db.String(255))  # 动物图片路径
    简介 = db.Column(db.Text)  # 动物简介
    Url = db.Column(db.String(255))  # 动物详情页链接
    sel=db.Column(db.Integer,default=0) # 是否被首页管理选中并排序显示

    # 获取所有动物类别，去重后返回
     # 获取所有动物类别，并按分类下动物数量排序
    @classmethod
    def get_all_animalClass(cls):
        # 查询每个分类下的动物数量，并按数量降序排序
        categories = db.session.query(
            cls.分类, 
            func.count(cls.id).label('count')
        ).group_by(cls.分类).order_by(func.count(cls.id).desc()).all()
        
        # 只返回分类名称的列表
        return [category[0] for category in categories]

    # 获取所有动物并按分类降序排序
    def get_all_animal():
        return animal.query.order_by(animal.分类.desc()).all()
    
    @staticmethod
    def get_all_pet_categories():
        """
        获取所有宠物分类，去重后返回分类名称列表
        """
        categories = db.session.query(animal.分类).distinct().all()
        return [category[0] for category in categories]



    # 获取热门宠物（默认前16条）
    def get_animal_hot():
        # 获取sel>0的宠物，按sel升序排序
        selected_pets = animal.query.filter(animal.sel > 0, animal.sel <17).order_by(animal.sel.asc()).all()
        # 如果不足16个，随机补充sel=0的宠物
        if len(selected_pets) < 16:
            remaining_count = 16 - len(selected_pets)
            # 获取所有sel=0的宠物并随机排序
            excluded_ids = [animal.id for animal in selected_pets]
            additional_pets = animal.query.filter(~animal.id.in_(excluded_ids)).order_by(func.rand()).limit(remaining_count).all()
            return selected_pets + additional_pets
        else:
            return selected_pets[:16]
    
    # 根据分类获取动物，如果分类为"热门宠物"则获取前16条记录
    def get_animal_by_class(cls):
        if cls == "热门宠物":
            return animal.get_animal_hot()
        elif cls == "全部":
            return animal.query.all()
        else:
            class_animals = animal.query.filter(animal.分类 == cls).all()
            return class_animals

    # 根据分类获取第一条动物记录
    def getClassFirst(cls):
        return animal.query.filter(animal.分类 == cls).first()

    # 根据ID获取单个动物记录
    def get_animal_by_id(id):
        return animal.query.filter(animal.id == id).first()

    def to_dict(self):
        """将动物数据转换为字典格式"""
        return {
            'id': self.id,
            '全名': self.全名,
            '别名': self.别名,
            '分类': self.分类,
            '体型': self.体型,
            '毛发': self.毛发,
            '智商': self.智商,
            '寿命': self.寿命,
            '饲养': self.饲养,
            '功能': self.功能,
            '原产地': self.原产地,
            '价格': self.价格,
            'imgUrl': self.imgUrl,
            'imgPath': self.imgPath,
            '简介': self.简介,
            'Url': self.Url
        }


# 文章模型，表示数据库中文章信息的表结构
class articles(db.Model):
    __tablename__ = 'articles'  # 表名

    # 定义字段
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)  # 文章ID，主键，自增
    title = db.Column(db.String(255), nullable=False)  # 文章标题，不允许为空
    view_date = db.Column(db.DateTime)  # 文章查看日期
    url = db.Column(db.String(255))  # 文章URL
    contents_json = db.Column(db.Text)  # 文章内容
    column = db.Column(db.String(255))  # 文章所属栏目
    sel=db.Column(db.Integer,default=0) # 是否被首页管理选中并排序显示

    # 获取热门文章列表（前10条）
    def hotArticleslist():
        return articles.query.order_by(articles.view_date.desc()).limit(10).all()

    # 根据栏目获取热门维基文章（前3条）
    def getHotWikeArticle(column):
        return articles.query.filter(articles.column == column).order_by(articles.view_date.desc()).limit(3).all()

    # 获取分页文章列表
    def get_article_page(page=1, per_page=15, order_by='id'):
        sort_column = getattr(articles, order_by, articles.id)
        return articles.query.order_by(sort_column).offset((page-1)*per_page).limit(per_page).all()

    # 获取热门轮播文章（前5条）
    def hotCarousel():
        return articles.query.order_by(func.rand()).limit(5).all()
    # 根据栏目获取最新文章（前3条）
    def getAnimeNew1(cl):
        return articles.query.filter(articles.column == cl).order_by(articles.view_date.desc()).limit(3).all()
    # 根据标题搜索文章，并返回指定范围的文章
    def find_article_by_title(find_title, num=None):
        if num>= 2:
            return articles.query.filter(articles.title.contains(find_title)).offset((num-1)*10).limit(10).all()
        else:
            return articles.query.filter(articles.title.contains(find_title)).limit(10).all()


    # 根据栏目获取指定数量的文章
    def getArticlesColumn(cl, num):
        return articles.query.filter(articles.column == cl).order_by(articles.view_date.desc()).limit(num).all()

    # 根据ID获取单篇文章
    def getIdArticle(id):
        return articles.query.filter(articles.id == id).first()

    def to_dict(self):
        """将文章数据转换为字典格式"""
        return {
            'id': self.id,
            'title': self.title,
            'view_date': self.view_date.strftime('%Y-%m-%d %H:%M:%S') if self.view_date else None,
            'url': self.url,
            'contents_json': self.contents_json,
            'column': self.column
        }
        
# 用户模型
class User(db.Model):
    __tablename__ = 'users'  # 表名

    # 定义字段
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)  # 用户ID，主键，自增
    username = db.Column(db.String(80), unique=True, nullable=False)  # 用户名，唯一，不允许为空
    email = db.Column(db.String(120), unique=True, nullable=False)  # 用户邮箱，唯一，不允许为空
    password = db.Column(db.String(128), nullable=False)  # 用户密码（明文），不允许为空
    password_hash = db.Column(db.String(128), nullable=False)  # 用户密码哈希值，不允许为空
    register_time = db.Column(db.DateTime, default=datetime.now)  # 用户注册时间，默认当前时间
    bio = db.Column(db.Text)  # 用户简介
    last_login = db.Column(db.DateTime) # 最后登录时间
    gender = db.Column(db.String(10))  # 用户性别
    age = db.Column(db.Integer)  # 用户年龄


    replies = db.relationship('Reply', backref='user_replay', lazy=True)  # 与回复的关系

    def set_password(self,password):
        self.password_hash = hashlib.md5(password.encode('utf-8')).hexdigest()


    def update_last_login(self):
        """更新最后登录时间"""
        self.last_login = datetime.now()
        db.session.commit()

    def to_dict(self):
        """将用户数据转换为字典格式"""
        return {
            'id': self.id,
            'username': self.username,
            'bio': self.bio,
            'email': self.email,
            'last_login': self.last_login.strftime('%Y-%m-%d %H:%M:%S') if self.last_login else None,
            'password':self.password,
            'password_hash': self.password_hash,
            'register_time': self.register_time.strftime('%Y-%m-%d %H:%M:%S') if self.register_time else None,
            'gender': self.gender,
            'age': self.age
        }

# 帖子模型，表示数据库中帖子信息的表结构
class Tiezi(db.Model):
    __tablename__ = 'tiezis'  # 表名

    # 定义字段
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)  # 帖子ID，主键，自增
    title = db.Column(db.String(100), nullable=False)  # 帖子标题，不允许为空
    content = db.Column(db.Text, nullable=False)
    create_time = db.Column(db.DateTime, default=datetime.now)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    like_num = db.Column(db.Integer, default=0)
    replies = db.relationship('Reply', backref='tiezi_replay', lazy=True)  # 与回复的关系

    # 获取所有帖子列表

    # 获取分页帖子列表，每页20条
    @staticmethod
    def getTieziList(page):
        per_page = 20
        # 获取分页数据
        tiezi_list = Tiezi.query.offset((page - 1) * per_page).limit(per_page).all()
        return tiezi_list

    def like_num_add(id):
        tiezi = Tiezi.query.filter(Tiezi.id == id).first()
        tiezi.like_num += 1
        db.session.commit()
        return tiezi.like_num

    def to_dict(self):
        """将帖子数据转换为字典格式"""
        return {
            'id': self.id,
            'title': self.title,
            'content': self.content,
            'create_time': self.create_time.strftime('%Y-%m-%d %H:%M:%S') if self.create_time else None,
            'user_id': self.user_id,
            'like_num': self.like_num
        }


# 回复模型，表示数据库中回复信息的表结构
class Reply(db.Model):
    __tablename__ = 'replys'  # 表名

    # 定义字段
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)  # 回复ID，主键，自增
    content = db.Column(db.Text, nullable=False)
    reply_time = db.Column(db.DateTime, default=datetime.now)
    like_num = db.Column(db.Integer, default=0)
    post_id = db.Column(db.Integer, db.ForeignKey('tiezis.id'), nullable=False)  # 所属帖子ID，外键，不允许为空
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)  # 发布者用户ID，外键，不允许为空


    def getTieziReplys(post_id, page):
        per_page =20
        return Reply.query.filter(Reply.post_id == post_id).order_by(Reply.like_num.desc()).offset((page - 1) * per_page).limit(20).all()
    
    def like_num_add(id):
        reply = Reply.query.filter(Reply.id == id).first()
        reply.like_num += 1
        db.session.commit()
        return reply.like_num
    

# 归档表
class Archive(db.Model):
    __tablename__ = 'archives'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    original_id = db.Column(db.Integer, nullable=False)  # 原始数据ID
    type = db.Column(db.String(20), nullable=False)  # 数据类型：user/article/pet
    title = db.Column(db.String(255))  # 标题或名称
    content = db.Column(db.Text)  # 完整的数据内容，以JSON字符串形式存储
    deleted_at = db.Column(db.DateTime, default=datetime.now)  # 删除时间
    reason = db.Column(db.String(255))  # 删除原因
    @classmethod
    def add_archive(cls, original_id, data_type, data_content, reason='用户删除'):
        """添加归档记录"""
        title = data_content.get('title', '') or data_content.get('username', '') or data_content.get('全名', '')
        archive = cls(
            original_id=original_id,
            type=data_type,
            title=title,
            content=json.dumps(data_content, ensure_ascii=False),
            reason=reason
        )
        db.session.add(archive)
        db.session.commit()
        return archive
    @classmethod
    def get_archives(cls, data_type=None, page=1, per_page=10):
        """获取归档列表，支持按类型筛选"""
        query = cls.query
        if data_type:
            query = query.filter_by(data_type=data_type)
        return query.order_by(cls.archive_time.desc()).paginate(
            page=page, per_page=per_page, error_out=False
        )

    @classmethod
    def restore_archive(cls, archive_id):
        """恢复归档的数据"""
        archive = cls.query.get(archive_id)
        if archive:
            archive.is_deleted = False
            db.session.commit()
            return archive
        return None

    @classmethod
    def delete_permanently(cls, archive_id):
        """永久删除归档记录"""
        archive = cls.query.get(archive_id)
        if archive:
            db.session.delete(archive)
            db.session.commit()
            return True
        return False









class AdminUser(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True, nullable=False)
    password_hash = db.Column(db.String(128), nullable=False)

    def set_password(self, password):
        self.password_hash = hashlib.md5(password.encode('utf-8')).hexdigest()

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)